import 'dart:math';

import 'package:flutter/material.dart';
import 'package:xsdk_flutter/xsdk/framework/base/xsdk_widget_stateful.dart';

/*
动态波浪 百分比
参考: https://blog.csdn.net/newlw/article/details/125927921

使用:
XWidgetUtils.getWidgetWave();

 */
class XWaveState extends XState<XStatefulWidget> with TickerProviderStateMixin{

  String? text;
  double fontSize;
  Color backgroundColor;
  Color waveColor;
  double currentWaveHeight;
  bool isCircleLayout;

  late AnimationController _waveController;
  late Animation<double> _waveAnimation;

  XWaveState({
    required this.currentWaveHeight,//0~100
    this.text,
    this.fontSize=18,
    this.backgroundColor=Colors.white,
    this.waveColor=Colors.lightBlue,
    this.isCircleLayout=true,
  });


  @override
  Widget onBuild(BuildContext context) {

    return RepaintBoundary(
      child: CustomPaint(
        painter: _XWavePainter(
          text: text,
          fontSize: fontSize,
          animatedControllerValue: _waveController.value,
          backgroundColor: backgroundColor,
          waveColor: waveColor,
          currentWaveHeight:currentWaveHeight,
          isCircleLayout:isCircleLayout,
        ),
      ),
    );

  }

  @override
  void onCreate() {
    //初始化波浪动画
    _initAnimations();
  }

  @override
  void onDestroy() {
  }

  @override
  void dispose() {
    //TickerProviderStateMixin
    _disposeAnimations();
    super.dispose();
  }

  @override
  void onStart() {
  }

  @override
  void onStop() {
  }

  @override
  Future<void> updateData({int pageIndex = 1}) async {
  }

  //////////////////

  //释放控制器 ok
  void _disposeAnimations() {
    _waveController.dispose();
  }

  //初始化波浪动画 ok
  void _initAnimations(){

    _waveController=AnimationController(
        duration: const Duration(milliseconds: 6000),
        vsync: this
    );

    // _waveAnimation=Tween(begin: 0.0, end: 1.0).animate(_waveController);
    // _waveController.addListener(() => setState(() {}));
    // _waveController.forward();
    // _waveController.addStatusListener((status) {
    //   switch (status) {
    //     case AnimationStatus.completed:
    //       XLogUtils.printLog('---AnimationStatus.completed');
    //       _waveController.repeat();
    //       break;
    //     case AnimationStatus.dismissed:
    //       _waveController.forward();
    //       break;
    //     default:
    //       break;
    //   }
    // });

    _waveAnimation = Tween(
      begin: 0.0,
      end: 1.0,
    ).animate(_waveController)
      ..addListener(() {
        setState(() => {});
      });
    _waveController.repeat();

  }


}

class _XWavePainter extends CustomPainter {

  String? text;
  double fontSize;
  Color? textColor;
  double animatedControllerValue;
  Color backgroundColor;
  Color waveColor;
  Color? borderColor;
  double borderWidth=0;
  //是否圆形widget
  bool isCircleLayout;
  //圆角矩形时使用
  double topLeftRadius=0;
  double topRightRadius=0;
  double bottomLeftRadius=0;
  double bottomRightRadius=0;

  //波浪高度占比值
  double currentWaveHeight; //0~100


  _XWavePainter({
    this.text,
    required this.animatedControllerValue, //_waveController.value
    required this.backgroundColor,
    required this.waveColor,
    required this.currentWaveHeight,
    this.fontSize=18,
    this.isCircleLayout=false,

  }){
    if(currentWaveHeight<0){
      currentWaveHeight=0;
    }else if(currentWaveHeight>100){
      currentWaveHeight=100;
    }

    textColor??=waveColor;
    borderColor??=waveColor.withOpacity(0.2);

  }



  @override
  void paint(Canvas canvas, Size size) {
    double outSide = min(size.width, size.height);
    double inSide = outSide-borderWidth*2;

    //外边框
    if(borderWidth>0){
      Paint boarderPaint = Paint()
        ..isAntiAlias = true
        ..color = borderColor!
        ..style = PaintingStyle.fill
        ..strokeWidth = 1;

      Path borderPath = Path();
      if(isCircleLayout){
        //canvas.drawCircle(Offset(side/2, side/2), side / 2, boarderPaint);
        borderPath.addOval(
            Rect.fromCircle(
                center: Offset(outSide/2, outSide/2),
                radius:outSide / 2
            )
        );
      }else{
        borderPath.addRRect(
            RRect.fromLTRBAndCorners(
              0, 0, outSide, outSide,
              topLeft: Radius.circular(topLeftRadius),
              topRight: Radius.circular(topRightRadius),
              bottomLeft: Radius.circular(bottomLeftRadius),
              bottomRight: Radius.circular(bottomRightRadius),
            )
        );
      }
      canvas.drawPath(borderPath, boarderPaint);
    }

    //背景
    Paint backgroundColorPaint = Paint()
      ..isAntiAlias = true
      ..style = PaintingStyle.fill
      ..strokeWidth = 1
      ..color = backgroundColor;
    Path backgroundColorPath = Path();

    if(isCircleLayout){
      backgroundColorPath.addOval(Rect.fromCircle(
          center: Offset(outSide/2, outSide/2), radius:inSide / 2));
    }else{
      backgroundColorPath.addRRect(
          RRect.fromLTRBAndCorners(
            borderWidth, borderWidth, inSide, inSide,
            topLeft: Radius.circular(topLeftRadius),
            topRight: Radius.circular(topRightRadius),
            bottomLeft: Radius.circular(bottomLeftRadius),
            bottomRight: Radius.circular(bottomRightRadius),
          )
      );
    }

    canvas.drawPath(backgroundColorPath, backgroundColorPaint);

    //文字
    _drawText(canvas: canvas, side: outSide, color: textColor!);

    //波浪(用于交集截取)
    Path circlePath = Path();
    // circlePath.addOval(
    //     Rect.fromCircle(
    //         center: Offset(outSide/2, outSide/2),
    //         radius:inSide / 2
    //     )
    // );
    if(isCircleLayout){
      circlePath.addArc(Rect.fromLTWH(borderWidth, borderWidth, inSide, inSide), 0, 2 * pi);
    }else{
      circlePath.addRRect(
          RRect.fromLTRBAndCorners(
            borderWidth, borderWidth, inSide, inSide,
            topLeft: Radius.circular(topLeftRadius),
            topRight: Radius.circular(topRightRadius),
            bottomLeft: Radius.circular(bottomLeftRadius),
            bottomRight: Radius.circular(bottomRightRadius),
          )
      );
    }

    //canvas.drawPath(circlePath, backgroundColorPaint);

    //波浪1
    Path wavePath1 = Path();
    double waveWidth1 = outSide * 1.8;
    double waveHeight1 = outSide / 6;
    /*
    动画:只要不断改变贝塞尔曲线的起始点坐标，使之不断从左往右移动，就可以营造出波浪从左往右前进的效果了。
    同时坐标也是波浪高度占比位置
     */
    wavePath1.moveTo((animatedControllerValue - 1) * waveWidth1, outSide*(1-currentWaveHeight/100));

    /*
    绘制了一个相对二次贝塞尔曲线
    注意: quadraticBezierTo 使用绝对坐标, relativeQuadraticBezierTo 使用相对坐标
     */
    for (double i = -waveWidth1; i < outSide; i += waveWidth1) {
      wavePath1.relativeQuadraticBezierTo(
          waveWidth1 / 4,
          -waveHeight1,
          waveWidth1 / 2,
          0
      );
      wavePath1.relativeQuadraticBezierTo(
          waveWidth1 / 4,
          waveHeight1,
          waveWidth1 / 2,
          0
      );
    }

    /*
    此时绘制的曲线还处于非闭合状态，需要将 wavePath 的首尾两端连接起来，这样后面才可以和 circlePath 取交集
    relativeLineTo 相对当前点坐标的最终坐标
    lineTo 绝对坐标
     */
    //wavePath1.relativeLineTo(0, radius1);
    wavePath1.lineTo(waveWidth1, outSide);
    wavePath1.lineTo(-waveWidth1, outSide);
    wavePath1.close();


    Paint warePaint1 = Paint()
      ..isAntiAlias = true
      ..style = PaintingStyle.fill
      ..strokeWidth = 1
      ..color = waveColor.withOpacity(0.15);

    //用于调试wavePath绘制出来，实际上不需要
    //canvas.drawPath(wavePath1, warePaint1);

    //取交集区域
    Path combinePath1 = Path.combine(PathOperation.intersect, circlePath, wavePath1);
    canvas.drawPath(combinePath1, warePaint1);
    //canvas.clipPath(combinePath1);

    //波浪2
    Path wavePath = Path();
    double waveWidth = outSide * 2;
    double waveHeight = outSide / 10;
    /*
    动画:只要不断改变贝塞尔曲线的起始点坐标，使之不断从左往右移动，就可以营造出波浪从左往右前进的效果了。
    同时坐标也是波浪高度占比位置
     */
    wavePath.moveTo((animatedControllerValue - 1) * waveWidth, outSide*(1-currentWaveHeight/100));

    /*
    绘制了一个相对二次贝塞尔曲线
    注意: quadraticBezierTo 使用绝对坐标, relativeQuadraticBezierTo 使用相对坐标
     */
    for (double i = -waveWidth; i < outSide; i += waveWidth) {
      wavePath.relativeQuadraticBezierTo(
          waveWidth / 4,
          -waveHeight,
          waveWidth / 2,
          0
      );
      wavePath.relativeQuadraticBezierTo(
          waveWidth / 4,
          waveHeight,
          waveWidth / 2,
          0
      );
    }

    /*
    此时绘制的曲线还处于非闭合状态，需要将 wavePath 的首尾两端连接起来，这样后面才可以和 circlePath 取交集
    relativeLineTo 相对当前点坐标的最终坐标
    lineTo 绝对坐标
     */
    // wavePath.relativeLineTo(0, radius);
    // wavePath.lineTo(outSide, outSide);
    // wavePath.lineTo(-waveWidth, outSide);
    wavePath.lineTo(waveWidth, outSide);
    wavePath.lineTo(-waveWidth, outSide);
    wavePath.close();


    Paint warePaint = Paint()
      ..isAntiAlias = true
      ..style = PaintingStyle.fill
      ..strokeWidth = 1
      ..color = waveColor;

    //用于调试wavePath绘制出来，实际上不需要
    //canvas.drawPath(wavePath, warePaint);

    //取交集区域
    Path combinePath = Path.combine(PathOperation.intersect, circlePath, wavePath);
    canvas.drawPath(combinePath, warePaint);
    // canvas.clipPath(combinePath);

    //并集
    Path combinePathX = Path.combine(PathOperation.union, combinePath1, combinePath);
    canvas.clipPath(combinePathX);

    //最后绘制文字(在交集区内) 顺序ok
    _drawText(canvas: canvas, side: outSide, color: backgroundColor);


  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    //是否重新绘制(自动动画)
    return animatedControllerValue != (oldDelegate as _XWavePainter).animatedControllerValue;
  }

  //中间文字
  void _drawText(
      {
        required Canvas canvas,
        required double side,
        required Color color
      }
      )
  {
    // ParagraphBuilder paragraphBuilder = ParagraphBuilder(
    //     ParagraphStyle(
    //       textAlign: TextAlign.center,
    //       fontStyle: FontStyle.normal,
    //       fontSize: fontSize,
    //     )
    // );
    // paragraphBuilder.pushStyle(TextStyle(color: color));
    // paragraphBuilder.addText(text);
    // ParagraphConstraints pc = ParagraphConstraints(width: fontSize);
    // Paragraph paragraph = paragraphBuilder.build()..layout(pc);
    // canvas.drawParagraph(
    //   paragraph,
    //   Offset(
    //       (side - paragraph.width) / 2.0,
    //       (side - paragraph.height) / 2.0
    //   ),
    // );

    text ??= '$currentWaveHeight%';

    TextSpan span = TextSpan(
      style: TextStyle(color: color, fontSize: fontSize),
      text: text,
    );
    TextPainter tp = TextPainter(
      text: span,
      textAlign: TextAlign.center,
      textDirection: TextDirection.ltr,
    );
    tp.layout();
    tp.paint(canvas, Offset(side / 2 - tp.width / 2, side / 2 - tp.height / 2));
  }

}



class _XWavePainter1 extends CustomPainter {

  String? text;
  double fontSize=14;
  Color? textColor;
  double animatedControllerValue;
  Color backgroundColor;
  Color waveColor;
  Color borderColor=Colors.transparent;
  double borderWidth=0;

  //波浪高度占比值
  double currentWaveHeight; //0~100


  _XWavePainter1({
    required this.animatedControllerValue, //_waveController.value
    required this.backgroundColor,
    required this.waveColor,
    required this.currentWaveHeight,
  }){
    if(currentWaveHeight<0){
      currentWaveHeight=0;
    }else if(currentWaveHeight>100){
      currentWaveHeight=100;
    }

    textColor??=waveColor;

  }



  @override
  void paint(Canvas canvas, Size size) {
    double outSide = min(size.width, size.height);
    double inSide = outSide-borderWidth*2;

    //外边框
    if(borderWidth>0){
      Paint boarderPaint = Paint()
        ..isAntiAlias = true
        ..color = borderColor
        ..style = PaintingStyle.fill
        ..strokeWidth = 1;
      //canvas.drawCircle(Offset(side/2, side/2), side / 2, boarderPaint);
      Path borderPath = Path();
      borderPath.addOval(Rect.fromCircle(
          center: Offset(outSide/2, outSide/2), radius:outSide / 2));
      canvas.drawPath(borderPath, boarderPaint);
    }

    //背景
    Paint backgroundColorPaint = Paint()
      ..isAntiAlias = true
      ..style = PaintingStyle.fill
      ..strokeWidth = 1
      ..color = backgroundColor;
    Path backgroundColorPath = Path();
    backgroundColorPath.addOval(Rect.fromCircle(
        center: Offset(outSide/2, outSide/2), radius:inSide / 2));
    canvas.drawPath(backgroundColorPath, backgroundColorPaint);

    //文字
    _drawText(canvas: canvas, side: outSide, color: textColor!);

    //波浪(用于交集截取)
    Path circlePath = Path();
    // circlePath.addOval(
    //     Rect.fromCircle(
    //         center: Offset(outSide/2, outSide/2),
    //         radius:inSide / 2
    //     )
    // );
    circlePath.addArc(Rect.fromLTWH(borderWidth, borderWidth, inSide, inSide), 0, 2 * pi);
    //canvas.drawPath(circlePath, backgroundColorPaint);

    //波浪
    Path wavePath = Path();
    double waveWidth = outSide * 2;
    double waveHeight = outSide / 10;
    double radius = outSide / 2;
    /*
    动画:只要不断改变贝塞尔曲线的起始点坐标，使之不断从左往右移动，就可以营造出波浪从左往右前进的效果了。
    同时坐标也是波浪高度占比位置
     */
    wavePath.moveTo((animatedControllerValue - 1) * waveWidth, outSide*(1-currentWaveHeight/100));

    /*
    绘制了一个相对二次贝塞尔曲线
    注意: quadraticBezierTo 使用绝对坐标, relativeQuadraticBezierTo 使用相对坐标
     */
    for (double i = -waveWidth; i < outSide; i += waveWidth) {
      wavePath.relativeQuadraticBezierTo(
          waveWidth / 4,
          -waveHeight,
          waveWidth / 2,
          0
      );
      wavePath.relativeQuadraticBezierTo(
          waveWidth / 4,
          waveHeight,
          waveWidth / 2,
          0
      );
    }

    /*
    此时绘制的曲线还处于非闭合状态，需要将 wavePath 的首尾两端连接起来，这样后面才可以和 circlePath 取交集
    relativeLineTo 相对当前点坐标的最终坐标
    lineTo 绝对坐标
     */
    wavePath.relativeLineTo(0, radius);
    wavePath.lineTo(outSide, outSide);
    wavePath.lineTo(-waveWidth, outSide);
    wavePath.close();


    Paint warePaint = Paint()
      ..isAntiAlias = true
      ..style = PaintingStyle.fill
      ..strokeWidth = 1
      ..color = waveColor;

    //用于调试wavePath绘制出来，实际上不需要
    //canvas.drawPath(wavePath, warePaint);

    //取交集区域
    final combinePath = Path.combine(PathOperation.intersect, circlePath, wavePath);
    canvas.drawPath(combinePath, warePaint);
    canvas.clipPath(combinePath);

    //最后绘制文字(在交集区内) 顺序ok
    _drawText(canvas: canvas, side: outSide, color: backgroundColor);


  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    //是否重新绘制(自动动画)
    return animatedControllerValue != (oldDelegate as _XWavePainter).animatedControllerValue;
  }

  //中间文字
  void _drawText(
      {
        required Canvas canvas,
        required double side,
        required Color color
      }
      )
  {
    // ParagraphBuilder paragraphBuilder = ParagraphBuilder(
    //     ParagraphStyle(
    //       textAlign: TextAlign.center,
    //       fontStyle: FontStyle.normal,
    //       fontSize: fontSize,
    //     )
    // );
    // paragraphBuilder.pushStyle(TextStyle(color: color));
    // paragraphBuilder.addText(text);
    // ParagraphConstraints pc = ParagraphConstraints(width: fontSize);
    // Paragraph paragraph = paragraphBuilder.build()..layout(pc);
    // canvas.drawParagraph(
    //   paragraph,
    //   Offset(
    //       (side - paragraph.width) / 2.0,
    //       (side - paragraph.height) / 2.0
    //   ),
    // );

    text ??= '$currentWaveHeight%';

    TextSpan span = TextSpan(
      style: TextStyle(color: color, fontSize: fontSize),
      text: text,
    );
    TextPainter tp = TextPainter(
      text: span,
      textAlign: TextAlign.center,
      textDirection: TextDirection.ltr,
    );
    tp.layout();
    tp.paint(canvas, Offset(side / 2 - tp.width / 2, side / 2 - tp.height / 2));
  }

}

